{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 1, Topic 1: Introduction to Clock Glitching (MAIN)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *Microcontrollers and FPGAs have a number of operating conditions that must be met in order for the device to work properly. Outside of these conditions, devices will begin to malfunction, with more extreme violations causing the device to stop entirely or even become damaged. By going outside these operating conditions for very small amounts of time, we can cause a varitey of temporary malfunctions*\n",
    "\n",
    "*In this lab, we'll explore clock glitching, which inserts short glitches into a device's clock. This will be used to get a target that's summing numbers in a loop to arrive at the wrong result.*\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "\n",
    "* Understand effects of clock glitching\n",
    "* Exploring ChipWhisperer's glitch module\n",
    "* Using clock glitching to disrupt a target's algorithm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Clock Glitching Theory\n",
    "\n",
    "Digital hardware devices almost always expect some form of reliable clock. We can manipulate the clock being presented to the device to cause unintended behaviour. We'll be concentrating on microcontrollers here, however other digital devices (e.g. hardware encryption accelerators) can also have faults injected using this technique.\n",
    "\n",
    "Consider a microcontroller first. The following figure is an excerpt from the Atmel AVR ATMega328P datasheet:\n",
    "\n",
    "![A2_1](img/Mcu-unglitched.png)\n",
    "\n",
    "Rather than loading each instruction from FLASH and performing the entire execution, the system has a pipeline to speed up the execution process. This means that an instruction is being decoded while the next one is being retrieved, as the following diagram shows:\n",
    "\n",
    "![A2_2](img/Clock-normal.png)\n",
    "\n",
    "But if we modify the clock, we could have a situation where the system doesn't have enough time to actually perform an instruction. Consider the following, where Execute #1 is effectively skipped. Before the system has time to actually execute it another clock edge comes, causing the microcontroller to start execution of the next instruction:\n",
    "\n",
    "![A2_3](img/Clock-glitched.png)\n",
    "\n",
    "This causes the microcontroller to skip an instruction. Such attacks can be immensely powerful in practice. Consider for example the following code from `linux-util-2.24`:\n",
    "\n",
    "```C\n",
    "/*\n",
    " *   auth.c -- PAM authorization code, common between chsh and chfn\n",
    " *   (c) 2012 by Cody Maloney <cmaloney@theoreticalchaos.com>\n",
    " *\n",
    " *   this program is free software.  you can redistribute it and\n",
    " *   modify it under the terms of the gnu general public license.\n",
    " *   there is no warranty.\n",
    " *\n",
    " */\n",
    "\n",
    "#include \"auth.h\"\n",
    "#include \"pamfail.h\"\n",
    "\n",
    "int auth_pam(const char *service_name, uid_t uid, const char *username)\n",
    "{\n",
    "    if (uid != 0) {\n",
    "        pam_handle_t *pamh = NULL;\n",
    "        struct pam_conv conv = { misc_conv, NULL };\n",
    "        int retcode;\n",
    "\n",
    "        retcode = pam_start(service_name, username, &conv, &pamh);\n",
    "        if (pam_fail_check(pamh, retcode))\n",
    "            return FALSE;\n",
    "\n",
    "        retcode = pam_authenticate(pamh, 0);\n",
    "        if (pam_fail_check(pamh, retcode))\n",
    "            return FALSE;\n",
    "\n",
    "        retcode = pam_acct_mgmt(pamh, 0);\n",
    "        if (retcode == PAM_NEW_AUTHTOK_REQD)\n",
    "            retcode =\n",
    "                pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);\n",
    "        if (pam_fail_check(pamh, retcode))\n",
    "            return FALSE;\n",
    "\n",
    "        retcode = pam_setcred(pamh, 0);\n",
    "        if (pam_fail_check(pamh, retcode))\n",
    "            return FALSE;\n",
    "\n",
    "        pam_end(pamh, 0);\n",
    "        /* no need to establish a session; this isn't a\n",
    "         * session-oriented activity...  */\n",
    "    }\n",
    "    return TRUE;\n",
    "}\n",
    "```\n",
    "\n",
    "This is the login code for the Linux OS. Note that if we could skip the check of `if (uid != 0)` and simply branch to the end, we could avoid having to enter a password. This is the power of glitch attacks - not that we are breaking encryption, but simply bypassing the entire authentication module! \n",
    "\n",
    "### Glitch Hardware\n",
    "\n",
    "The ChipWhisperer Glitch system uses the same synchronous methodology as its Side Channel Analysis (SCA) capture. A system clock (which can come from either the ChipWhisperer or the Device Under Test (DUT)) is used to generate the glitches. These glitches are then inserted back into the clock, although it's possible to use the glitches alone for other purposes (i.e. for voltage glitching, EM glitching).\n",
    "\n",
    "The generation of glitches is done with two variable phase shift modules, configured as follows:\n",
    "\n",
    "![A2_4](img/Glitchgen-phaseshift.png)\n",
    "\n",
    "In CW-Husky there is one important difference: the phase shift 1 output is not inverted before it is ANDed with the phase shift 2 output.\n",
    "\n",
    "The enable line is used to determine when glitches are inserted. Glitches can be inserted continuously (useful for development) or triggered by some event. The following figure shows how the glitch can be muxd to output to the Device Under Test (DUT).\n",
    "\n",
    "![A2_5](img/Glitchgen-mux.png)\n",
    "\n",
    "### Hardware Support: CW-Lite/Pro\n",
    "\n",
    "The phase shift blocks use the Digital Clock Manager (DCM) blocks within the FPGA. These blocks have limited support for run-time configuration of parameters such as phase delay and frequency generation, and for maximum performance the configuration must be fixed at design time. The Xilinx-provided run-time adjustment can shift the phase only by about +/- 5nS in 30pS increments (exact values vary with operating conditions).\n",
    "\n",
    "For most operating conditions this is insufficient - if attacking a target at 7.37MHz the clock cycle would have a period of 136nS. In order to provide a larger adjustment range, an advanced FPGA feature called Partial Reconfiguration (PR) is used. The PR system requires special partial bitstreams which contain modifications to the FPGA bitstream. These are stored as two files inside a \"firmware\" zip which contains both the FPGA bitstream along with a file called `glitchwidth.p` and a file called `glitchoffset.p`. If a lone bitstream is being loaded into the FPGA (i.e. not from the zip-file), the partial reconfiguration system is disabled, as loading incorrect partial reconfiguration files could damage the FPGA. This damage is mostly theoretical, more likely the FPGA will fail to function correctly.\n",
    "\n",
    "If in the course of following this tutorial you find the FPGA appears to stop responding (i.e. certain features no longer work correctly), it could be the partial reconfiguration data is incorrect.\n",
    "\n",
    "We'll look at how to interface with these features later in the tutorial.\n",
    "\n",
    "### Hardware Support: CW-Husky\n",
    "\n",
    "The clock-generation logic in Husky's 7-series FPGA is considerably different than the 6-series FPGAs used in CW-Lite/Pro. The DCM is gone and replaced by the much more powerful (and power hungry...) Mixed Mode Clock Manager (MMCM). In particular for our glitching application, MMCMs allow fine phase shift adjustments over an unlimited range, in steps as small as 15ps. And all this without having to dynamically reconfigure the FPGA bitfile! For this reason, the format for specifying the glitch offset and width is different from what it was for CW-Lite/Pro. Instead of specifiying a percentage of the source clock period, you now specify the actual number of phase shift steps. The duration of one phase shift step is 1/56 of the MMCM VCO clock period, which can itself be configured to be anyhwere in the range from 600 MHz to 1200 MHz (via `scope.clock.pll.update_fpga_vco()`).\n",
    "\n",
    "While the MMCM is more powerful than the DCM with respect to its features, it also requires a lot more power. For this reason, the glitch generation circuitry is disabled by default and must be explicitly turned on. Fear not, Husky also uses Xilinx's XADC module to continuously monitor its temperature, and all MMCMs are automatically turned off at when the temperature starts getting too high, well below dangerous levels are reached (run `scope.XADC` to see all its statistics and settings).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CW308_SAM4S'\n",
    "SS_VER = 'SS_VER_2_1'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"../../Setup_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$SS_VER\"\n",
    "cd ../../../firmware/mcu/simpleserial-glitch\n",
    "make PLATFORM=$1 CRYPTO_TARGET=NONE SS_VER=$2 -j"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = \"../../../firmware/mcu/simpleserial-glitch/simpleserial-glitch-{}.hex\".format(PLATFORM)\n",
    "cw.program_target(scope, prog, fw_path)\n",
    "if SS_VER=='SS_VER_2_1':\n",
    "    target.reset_comms()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll probably crash the target a few times while we're trying some glitching. Create a function to reset the target:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if PLATFORM == \"CWLITEXMEGA\":\n",
    "    def reboot_flush():            \n",
    "        scope.io.pdic = False\n",
    "        time.sleep(0.1)\n",
    "        scope.io.pdic = \"high_z\"\n",
    "        time.sleep(0.1)\n",
    "        #Flush garbage too\n",
    "        target.flush()\n",
    "else:\n",
    "    def reboot_flush():            \n",
    "        scope.io.nrst = False\n",
    "        time.sleep(0.05)\n",
    "        scope.io.nrst = \"high_z\"\n",
    "        time.sleep(0.05)\n",
    "        #Flush garbage too\n",
    "        target.flush()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Communication\n",
    "\n",
    "For this lab, we'll be introducing a new method: `target.simpleserial_read_witherrors()`. We're expecting a simpleserial response back; however, glitch will often cause the target to crash and return an invalid string. This method will handle all that for us. It'll also tell us whether the response was valid and what the error return code was. Use as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Do glitch loop\n",
    "target.simpleserial_write('g', bytearray([]))\n",
    "\n",
    "val = target.simpleserial_read_witherrors('r', 4, glitch_timeout=10)#For loop check\n",
    "valid = val['valid']\n",
    "if valid:\n",
    "    response = val['payload']\n",
    "    raw_serial = val['full_response']\n",
    "    error_code = val['rv']\n",
    "\n",
    "#print(bytearray(val['full_response'].encode('latin-1')))\n",
    "print(val)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Target Firmware\n",
    "\n",
    "For this lab, our goal is to get the following code to preduce an incorrect result:\n",
    "\n",
    "```C\n",
    "uint8_t glitch_loop(uint8_t* in)\n",
    "{\n",
    "    volatile uint16_t i, j;\n",
    "    volatile uint32_t cnt;\n",
    "    cnt = 0;\n",
    "    trigger_high();\n",
    "    for(i=0; i<50; i++){\n",
    "        for(j=0; j<50; j++){\n",
    "            cnt++;\n",
    "        }\n",
    "    }\n",
    "    trigger_low();\n",
    "    simpleserial_put('r', 4, (uint8_t*)&cnt);\n",
    "    return (cnt != 2500);\n",
    "}\n",
    "```\n",
    "\n",
    "As you can see, we've got a simple loop. This is a really good place to start glitching for 2 reasons:\n",
    "\n",
    "1. We've got a really long portion of time with a lot of instructions to glitch. In contrast, with the Linux example we're be trying to target a single instruction.\n",
    "\n",
    "1. For some glitching scenarios, we're looking for a pretty specific glitch effect. In the Linux example, we might be banking on the glitch causing the target to skip an instruction instead of corrupting the comparison since that's a lot more likely to get us where we want in the code path. For this simple loop calculation, pretty much any malfunction will show up in the result.\n",
    "\n",
    "## Glitch Module\n",
    "\n",
    "All the settings/methods for the glitch module can be accessed under `scope.glitch`. As usual, documentation for the settings and methods can be accessed on [ReadtheDocs](https://chipwhisperer.readthedocs.io/en/latest/scope-api.html) or with the python `help` command:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "help(scope.glitch)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### We'll first go over settings that differ between the CW Husky and the CW Lite/Pro:\n",
    "* clk_src\n",
    "\n",
    "> The clock signal that the glitch DCM is using as input. Can be set to \"target\" or \"clkgen\" In this case, we'll be providing the clock to the target, so we'll want this set to \"clkgen\".\n",
    "\n",
    "> On CW Husky, a separate PLL is used to clock the glitch module instead of the clkgen module. The equivalent setting here for \"clkgen\" is \"pll\"\n",
    "* offset\n",
    "\n",
    "> Where in the output clock to place the glitch. Can be in the range `[-48.8, 48.8]`. Often, we'll want to try many offsets when trying to glitch a target.\n",
    "\n",
    "> On CW Husky, the range will depend on frequency of the PLL used to drive the glitch module (settable which can be configured to be anyhwere in the range from 600 MHz to 1200 MHz via `scope.clock.pll.update_fpga_vco()`), but, when the glitch module is active, the range will be `[0, scope.glitch.phase_shift_steps]`.\n",
    "* width\n",
    "\n",
    "> How wide to make the glitch. Can be in the range `[-50, 50]`, though there is no reason to use widths < 0. Wider glitches more easily cause glitches, but are also more likely to crash the target, meaning we'll often want to try a range of widths when attacking a target.\n",
    "\n",
    "> Like offset, the range will be `[0, scope.glitch.phase_shift_steps]`.\n",
    "\n",
    "#### These settings, on the other hand, are the same between the Husky and the Lite/Pro:\n",
    "\n",
    "* output\n",
    "\n",
    "> The output produced by the glitch module. For clock glitching, clock_xor is often the most useful option, as this inverts the clock during the glitch.\n",
    "* ext_offset\n",
    "\n",
    "> The number of clock cycles after the trigger to put the glitch.\n",
    "* repeat\n",
    "\n",
    "> The number of clock cycles to repeat the glitch for. Higher values increase the number of instructions that can be glitched, but often increase the risk of crashing the target.\n",
    "\n",
    "* trigger_src\n",
    "\n",
    "> How to trigger the glitch. For this tutorial, we want to automatically trigger the glitch from the trigger pin only after arming the ChipWhipserer, so we'll use `ext_single`\n",
    "\n",
    "In addition, we'll need to tell ChipWhipserer to use the glitch module's output as a clock source for the target by setting `scope.io.hs2 = \"glitch\"`. We'll also setup a large `repeat` to make glitching easier.\n",
    "\n",
    "## CW Glitch Controller\n",
    "\n",
    "To make creating a glitch loop easier, ChipWhisperer includes a glitch controller. We'll start of by initializing it with different potential results of the attack. You define these to be whatever you want, but often three groups are sufficient:\n",
    "\n",
    "1. `\"success\"`, where our glitch had the desired effect\n",
    "1. `\"reset\"`, where our glitch had an undesirable effect. Often, this effect is crashing or resetting the target, which is why we're calling it `\"reset\"`\n",
    "1. `\"normal\"`, where you glitch didn't have a noticable effect.\n",
    "\n",
    "We also need to tell it what glitch parameters we want to scan through, in this case width and offset. We'll also add a \"tries\" parameter which, as the name suggests, is just there to try each setting multiple times:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc = cw.GlitchController(groups=[\"success\", \"reset\", \"normal\"], parameters=[\"width\", \"offset\", \"ext_offset\", \"tries\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One of the niceties of the glitch controller is that it can display our current settings. This will update in real time as we use the glitch controller!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.display_stats()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also make a settings map that can also update in realtime as well:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.glitch_plot(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here `plotdots` is a dictionary that specifies how you want to plot each group. In this case, we're plotting `\"success\"` as a green `+` (`\"+g\"`), `\"reset\"` as a red `x` (`\"xr\"`), and we won't be plotting glitch attempts where nothing abnormal happens (`None`)\n",
    "\n",
    "This plot will auto update its bounds as points are added. If you want to specify the axis bounds, you can do so as follows:\n",
    "\n",
    "```python\n",
    "gc.glitch_plot(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None}, x_bound=(-48, 48), y_bound=(-48, 48))\n",
    "```\n",
    "\n",
    "You can also select which parameters you want to use for x and y, either by index, or by its name:\n",
    "\n",
    "```python\n",
    "# will flip width and offset axes\n",
    "gc.glitch_plot(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None}, x_index=1, y_index=0)\n",
    "# or\n",
    "gc.glitch_plot(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None}, x_index=\"offset\", y_index=\"width\")\n",
    "\n",
    "```\n",
    "\n",
    "You can set ranges for each glitch setting:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.set_range(\"width\", -5, 5)\n",
    "gc.set_range(\"offset\", -5, 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Each setting moves from min to max based on the global step:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.set_global_step([5.0, 2.5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can print out all the glitch settings to see how this looks:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for glitch_setting in gc.glitch_values():\n",
    "    print(\"offset: {:4.1f}; width: {:4.1f}\".format(glitch_setting[1], glitch_setting[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can tell the glitch controller when you've reached a particular result state like so:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#gc.add(\"reset\", (scope.glitch.width, scope.glitch.offset)) or simply gc.add(\"reset\")\n",
    "#gc.add(\"success\", (scope.glitch.width, scope.glitch.offset)) or simply gc.add(\"success\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As of ChipWhisperer 5.7, you can skip the glitch width and glitch offset parameters. In this case, the glitch controller will use its internal values for the coordinates. Note that due to rounding, this will usually be a bit different from the actual hardware value on the Lite/Pro; however, the values will still correspond to the correct settings on your ChipWhisperer.\n",
    "\n",
    "We'll start off with the following settings. It's usually best to use \"clock_xor\" with clock glitching, which will insert a glitch if the clock is high or the clock is low.\n",
    "\n",
    "For CW-Husky, we must first explicitly turn on the glitch circuitry (it is off by default for power savings):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if scope._is_husky:\n",
    "    scope.glitch.enabled = True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll start off with the following settings. It's usually best to use \"clock_xor\" with clock glitching, which will insert a glitch if the clock is high or the clock is low."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Basic setup\n",
    "# set glitch clock\n",
    "if scope._is_husky:\n",
    "    scope.glitch.clk_src = \"pll\"\n",
    "else:\n",
    "    scope.glitch.clk_src = \"clkgen\" \n",
    "\n",
    "scope.glitch.output = \"clock_xor\" # glitch_out = clk ^ glitch\n",
    "scope.glitch.trigger_src = \"ext_single\" # glitch only after scope.arm() called\n",
    "\n",
    "scope.io.hs2 = \"glitch\"  # output glitch_out on the clock line\n",
    "print(scope.glitch)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These settings are often a good starting point for all clock glitching, so, new with ChipWhisperer 5.7, we've got a method that sets all of this up for you:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.cglitch_setup()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should have all you need to construct your glitch loop. We'll get you started, but the rest is up to you! Also, some stuff to keep in mind:\n",
    "\n",
    "* You'll need to detect crashes, successful glitches, and normal returns from the target. Don't be afraid to experiment with the loop: you can always restart it and rerun the code.\n",
    "* You can cover a larger set of glitch settings by starting with large glitch controller steps to get idea where some interesting locations are, then repeating the glitch loop with small steps in interesting areas. Where there's one successful glitch, there's probably more!\n",
    "* You can speed up your glitch campaign substantially by only plotting crashes and successes, since they're typically much rarer than normal behaviour in the target\n",
    "* On CW-Husky, glitch offset and width are specified in number of phase shift steps, whereas on CW-Lite/Pro, they are specified in percentage of clock period. The code provided below sets appropriate starting ranges for each case. Run `help(scope.glitch)` to understand this better."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm.notebook import trange\n",
    "import struct\n",
    "\n",
    "# width and offset numbers have a very different meaning for Husky vs Lite/Pro;\n",
    "# see help(scope.glitch) for details\n",
    "num_tries = 1\n",
    "gc.set_range(\"tries\", 1, num_tries)\n",
    "if scope._is_husky:\n",
    "    gc.set_range(\"width\", 0, scope.glitch.phase_shift_steps//2)\n",
    "    gc.set_range(\"offset\", 0, scope.glitch.phase_shift_steps)\n",
    "    gc.set_global_step([100]) # reduce if you don't get any glitches\n",
    "    scope.adc.lo_gain_errors_disabled = True\n",
    "    scope.adc.clip_errors_disabled = True\n",
    "else:\n",
    "    gc.set_range(\"width\", 0, 48)\n",
    "    gc.set_range(\"offset\", -48, 48)\n",
    "    gc.set_global_step([8, 4, 2, 1])\n",
    "    \n",
    "scope.glitch.repeat = 1\n",
    "gc.set_step(\"tries\", 1)\n",
    "scope.adc.timeout = 0.1\n",
    "gc.set_range(\"ext_offset\", 0, 40)\n",
    "gc.set_step(\"ext_offset\", 1)\n",
    "\n",
    "reboot_flush()\n",
    "broken = False\n",
    "for glitch_setting in gc.glitch_values():\n",
    "    scope.glitch.offset = glitch_setting[1]\n",
    "    scope.glitch.width = glitch_setting[0]\n",
    "    scope.glitch.ext_offset = glitch_setting[2]\n",
    "    # ###################\n",
    "    # Add your code here\n",
    "    # ###################\n",
    "    #raise NotImplementedError(\"Add your code here, and delete this.\")\n",
    "\n",
    "    # ###################\n",
    "    # START SOLUTION\n",
    "    # ###################\n",
    "    if scope.adc.state:\n",
    "        # can detect crash here (fast) before timing out (slow)\n",
    "        print(\"Trigger still high!\")\n",
    "        gc.add(\"reset\")\n",
    "\n",
    "        #Device is slow to boot?\n",
    "        reboot_flush()\n",
    "\n",
    "    scope.arm()\n",
    "\n",
    "    #Do glitch loop\n",
    "    target.simpleserial_write('g', bytearray([]))\n",
    "\n",
    "    ret = scope.capture()\n",
    "    \n",
    "    loff = scope.glitch.offset\n",
    "    lwid = scope.glitch.width\n",
    "\n",
    "    if ret:\n",
    "        print('Timeout - no trigger')\n",
    "        gc.add(\"reset\")\n",
    "\n",
    "        #Device is slow to boot?\n",
    "        reboot_flush()\n",
    "\n",
    "    else:\n",
    "        val = target.simpleserial_read_witherrors('r', 4, glitch_timeout=10, timeout=50)#For loop check\n",
    "        if val['valid'] is False:\n",
    "            gc.add(\"reset\")\n",
    "        else:\n",
    "\n",
    "            #print(val['payload'])\n",
    "            if val['payload'] is None:\n",
    "                print(val['payload'])\n",
    "                continue #what\n",
    "            #gcnt = struct.unpack(\"<b\", val['payload'])[0] #for code-flow check\n",
    "            gcnt = struct.unpack(\"<I\", val['payload'])[0]\n",
    "\n",
    "            #print(gcnt)                \n",
    "            # for table display purposes\n",
    "            #if gnt != 0: #for code-flow check\n",
    "            if gcnt != 2500: #for loop check\n",
    "                broken = True\n",
    "                gc.add(\"success\")\n",
    "                print(val['payload'])\n",
    "                print(\"🐙\", end=\"\")\n",
    "                break # <-- remove this to try for multiple glitches\n",
    "            else:\n",
    "                gc.add(\"normal\")\n",
    "    # ###################\n",
    "    # END SOLUTION\n",
    "    # ###################\n",
    "\n",
    "print(\"Done glitching\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Results\n",
    "\n",
    "In addition to plotting, the glitch controller also has the capability to return results as a list that groups paramters and results. These results give both the number of each result, as well as the rate of each result:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.calc()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also get results back with some parameters ignored. Results from parameters that now match will be grouped. This is particularly useful with something like the `\"tries\"` parameter, as you don't typically care whether a glitch was successful on your first, second, or third attempt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = gc.calc(ignore_params=\"tries\")\n",
    "results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, `calc()` can also sort by different results. A common use for this is to sort by success rate:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = gc.calc(ignore_params=\"tries\", sort=\"success_rate\")\n",
    "results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Plotting Glitch Results\n",
    "\n",
    "We can replot our glitch map using the `plot_2d()` method. Settings are similar to `glitch_plot()`. If `plotdots` are not specified, the same ones as the `glitch_plot()` will be used.\n",
    "\n",
    "`plot_2d()` also has the advantage of displaying an alpha channel. The hover tool, which allows you to see the coordinates by mousing over a plot point, has a separate button for each group on the right toolbar. This allows you to see, for example, only the hover information for successes by turning the reset hover off. The hover tool will also show the rate of occurrence for the group."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.plot_2d()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Make sure you write down those glitch settings, since we'll be using for the rest of the glitching labs! In fact, we'll be using a lot of the general code structure here for the rest of the labs, with the only big changes being:\n",
    "\n",
    "### Repeat\n",
    "\n",
    "This lab used a pretty large repeat value. Like the name suggests, this setting controls how many times the glitch is repeated (i.e. a repeat value of 5 will place glitches in 5 consecutive clock cycles). Consider that each glitch inserted has a chance to both cause a glitch or crash the device. This was pretty advantageous for this lab since we had a lot of different spots we wanted to place a glitch - using a high repeat value increased our chance for a crash, but also increased our chance for a successful glitch. For an attack where we're targeting a single instruction, we don't really increase our glitch chance at all, but still have the increased crash risk. Worse yet, a successful glitch in a wrong spot may also cause a crash! It is for that reason that it's often better to use a low repeat value when targeting a single instruction.\n",
    "\n",
    "### Ext Offset\n",
    "\n",
    "The ext offset setting controls a delay between the trigger firing and the glitch being inserted. Like repeat, it's base on whole clock cycles, meaning an ext offset of 10 will insert a glitch 10 cycles after the trigger fires. We didn't have to worry about this setting for this lab since the large repeat value was able to take us into the area we wanted. This won't be true for many applications, where you'll have to try glitches at a large variety of ext_offsets.\n",
    "\n",
    "### Success, Reset, and Normal\n",
    "\n",
    "These three result states are usually enough to describe most glitch results. What constitues a success, however, will change based on what firmware you're attacking. For example, if we were attacking the Linux authentication, we might base success on a check to see whether or not we're root."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#scope.dis()\n",
    "#target.dis()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert broken is True"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
